//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
using JetBrains.Annotations;
using LargoCommon.Abstract;
using LargoCommon.Interfaces;
using LargoCommon.Localization;
namespace LargoCommon.Music {
///
/// Musical Part.
///
public sealed class MusicalPart {
#region Fields
///
/// Musical Block.
///
private MusicalBlock musicalBlock;
///
/// Musical Track.
///
private IList musicalTracks;
///
/// Musical Objects.
///
private Collection musicalObjects;
#endregion
#region Constructors
///
/// Initializes a new instance of the MusicalPart class.
///
/// The given block.
public MusicalPart(MusicalBlock givenBlock)
{
this.MusicalBlock = givenBlock;
this.MusicalLines = new List();
this.MusicalObjects = new Collection();
}
///
/// Initializes a new instance of the class.
///
[UsedImplicitly]
public MusicalPart() {
}
#endregion
#region Public properties
///
/// Gets Musical Lines.
///
/// Property description.
public IList MusicalLines {
get
{
Contract.Ensures(Contract.Result>() != null);
return this.musicalTracks ?? (this.musicalTracks = new List());
}
//// Remove private set - DevExpress
private set => this.musicalTracks = value;
}
///
/// Gets or sets identifier.
///
/// Property description.
public string PartId { get; set; }
///
/// Gets or sets Instrument.
///
/// Property description.
public MusicalInstrument Instrument { get; set; }
///
/// Gets or sets Channel.
///
/// Property description.
public MidiChannel Channel { get; set; }
/// Gets or sets purpose of the track.
/// Property description.
/// Returns value.
public LinePurpose Purpose { get; set; } //// CA1044 (FxCop)
///
/// Gets or sets composed file.
///
/// Property description.
///
/// Gets or sets musical block.
///
/// Property description.
private MusicalBlock MusicalBlock {
get {
Contract.Ensures(Contract.Result() != null);
if (this.musicalBlock == null) {
throw new InvalidOperationException("Musical block is null.");
}
return this.musicalBlock;
}
set => this.musicalBlock = value ?? throw new ArgumentException(LocalizedMusic.String("Argument cannot be null."), nameof(value));
}
#endregion
#region Private properties
///
/// Gets or sets Part Number.
///
/// Property description.
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private int PartNumber { [UsedImplicitly] get; set; }
///
/// Gets or sets Musical Tones.
///
/// Property description.
private Collection MusicalObjects {
get
{
Contract.Ensures(Contract.Result>() != null);
return this.musicalObjects ?? (this.musicalObjects = new Collection());
}
set => this.musicalObjects = value;
}
#endregion
#region Static factory methods
///
/// Gets new musical track.
///
/// The musical block.
/// Number of part.
/// Midi Channel.
///
/// Returns value.
///
public static MusicalPart GetNewMusicalPart(MusicalBlock musicalBlock, int partNumber, MidiChannel givenChannel) {
var part = GetNewMusicalPart(musicalBlock);
part.PartNumber = partNumber;
part.Channel = givenChannel;
return part;
}
#endregion
#region Public methods
/// Add on musical tone to the end of part.
/// Musical object - tone or shift.
public void AddMusicalObject(IMusicalLocation musicalObject) {
Contract.Requires(musicalObject != null);
//// if (musicalObject == null) { return; }
this.MusicalObjects.Add(musicalObject);
}
///
/// Moves the objects to staff tracks.
///
public void MoveObjectsToStaffTracks() {
//// MusicalTones group by staff and voice
var trackGroups = (from mt in this.MusicalObjects
select new { mt.Staff, mt.InstrumentNumber }).Distinct().ToList(); //// mt.Channel
this.MusicalLines = new List();
foreach (var tg in trackGroups) {
var tg1 = tg;
var voiceObjects = (from mt in this.MusicalObjects
where mt.Staff == tg1.Staff && mt.InstrumentNumber == tg1.InstrumentNumber //// && mt.Channel == tg1.Channel
orderby mt.BarNumber
select mt).ToList();
if (!voiceObjects.Any()) {
continue;
}
var line = MusicalLine.GetNewMusicalLine(MusicalLineType.Melodic, this.MusicalBlock);
line.FirstStatus.Instrument = new MusicalInstrument((MidiMelodicInstrument)tg.InstrumentNumber);
//// track.FirstStatus.Channel = this.Channel;
//// track.FirstStatus.GChannel = new GeneralChannel(InstrumentGenus.Melodical, tg.Instrument, this.Channel);
line.Purpose = this.Purpose;
//// track.Purpose = this.Purpose; //// 2019/01
this.MusicalLines.Add(line);
voiceObjects.ForAll(musicalObject => {
if (musicalObject is MusicalStrike tone)
{
line.AddMusicalTone(tone);
}
});
}
}
///
/// Lays the objects to voice tracks.
///
public void LayObjectsToVoiceTracks() {
//// MusicalTones group by staff and voice
var trackGroups = (from mt in this.MusicalObjects
select new { mt.Staff, mt.Voice }).Distinct().ToList();
this.MusicalLines = new List();
foreach (var tg in trackGroups) {
var tg1 = tg;
var voiceObjects = (from mt in this.MusicalObjects
where mt.Staff == tg1.Staff && mt.Voice == tg1.Voice
select mt).ToList();
if (!voiceObjects.Any()) {
continue;
}
var line = MusicalLine.GetNewMusicalLine(0, this.MusicalBlock);
line.FirstStatus.Instrument = this.Instrument;
line.MainVoice.Channel = this.Channel;
//// track.Status.GChannel = new GeneralChannel(InstrumentGenus.Melodical, this.Instrument, this.Channel);
line.Purpose = this.Purpose;
//// track.Purpose = this.Purpose; //// 2019/01
this.MusicalLines.Add(line);
//// Values of BitFrom must be determined here !!!
var bitFrom = 0;
var lastBarNumber = -1;
voiceObjects.ForAll(musicalObject => {
if (musicalObject.BarNumber != lastBarNumber) {
bitFrom = 0;
lastBarNumber = musicalObject.BarNumber;
}
if (musicalObject is MusicalShift shift)
{
bitFrom = bitFrom + shift.Value;
}
// ReSharper disable once InvertIf
if (musicalObject is MusicalStrike tone && bitFrom >= 0)
{
tone.BitFrom = (byte)bitFrom;
line.AddMusicalTone(tone);
bitFrom = bitFrom + tone.Duration;
}
});
//// track.MusicalOctave = track.MusicalTones.
}
}
#endregion
#region Private methods
///
/// Gets new musical track.
///
/// The given block.
///
/// Returns value.
///
private static MusicalPart GetNewMusicalPart(MusicalBlock givenBlock) {
var part = new MusicalPart(givenBlock);
return part;
}
#endregion
}
}